ソフトウェアアーキテクチャの基礎輪読会 14章
日付:11/20
調査者:ichimura.icon,takasshii.icon
章のまとめ
takasshii.icon同じページでやろ!
ichimura.icon了解です!
要約
イベント駆動アーキテクチャ
memo
分散非同期型のアーキテクチャ
高度にスケーラブルで高パフォーマンスがアプリケーションが実現できる
弾力性も高い
今回ついにスケーラビリティ系が高いアーキテクチャ
非同期でシステムの全体的な応答性を向上させられる
イベントには通知や命令といった目的がある
mqtt通信をイメージするとわかりやすい
takasshii.iconIoTの通信でよく出てくるやつだね
pub/subの関係
比較的単純なイベント処理を持つ
高度な応答性と動的制御ができる
主要なアーキテクチャコンポーネント
図14-2を参照
開始イベント -> イベントブローカー -> イベントプロセッサー -> 処理イベント通知
複数のドメインベースの クラスター化 されたインスタンス
takasshii.iconUDP通信みたいだね
publish/subscribeのメッセージモデル
何をしたかも残りのシステムに伝え続ける
機能を追加する時の拡張性を提供
例: 通知イベントプロセッサ
電子メールを作成して送信、新しい処理イベントをトピックに送ることでシステムの残りの部分に伝える
例 典型的な小売店の注文入力システム
その前にざっくりと中身理解
各イベントプロセッサーはイベントチャンネルから流れるイベントを受け取る
イベントプロセッサーは、注目(サブスクライブ)しているイベントに合わせて処理を行う
処理の後、処理をしたことを伝えるイベントをイベントチャンネルに流す
こうして、各イベントプロセッサーが必要なイベントに対して処理を行う
必要ないものは基本無視する
OrderPlacement <- PlaceOrder
データベース上のテーブルに注文レコードを挿入
注文IDを顧客に渡す
order-createdを生成、システムの残りの部分に注文を作成したことを伝える
Notification, Payment, Inventoryのイベントプロセッサーは並列にタスクを実行する
Notification <- order-created
顧客に電子メールを送信
その後、email-sent を生成
待ち受けているプロセッサーはいないが、これにより 拡張性 を持たせられる
Inventry <- order-created
購入された書籍の在庫を減少させる
inventory-updated を生成して処理したことを伝える
warehouse <- inventory-updated
倉庫の在庫を見て少なくなればアイテムを再注文
inventory-resuppliedを生成
Payment <- order-created
顧客のクレジットカードに作成された注文を請求する
支払い成功時に payment-applied を生成
支払い失敗時に payment-denied を生成
クレジットカード情報の更新や、別の支払い方法を顧客に知らせる必要がある
Notification <- payment-denied
OrderFulfillment <- paymento-applied
注文のピッキングと梱包をする
完了したら order-fulfilled を生成
Notification <- order-fulfilled
Shipping <- order-fulfilled
出荷方法を決定して、order-shipped を生成
Nofication <- order-shipped
メリット
パフォーマンス
応答性
スケーラビリティ
デメリット
開始イベントに関連したワークフロー全体を制御できない
同期できないため、処理イベントが行われた詳細な時間などをイベントプロセッサーが把握できない
エラー処理
ビジネストランザクションを監視していないため、障害発生時にどの要素もクラッシュを認識できない
メディエーターはこの監視の役割を持っている
他の要素はエラーを気にすることなく処理を続ける
回復性もない
ichimura.icon お疲れ様です ☺️
takasshii.iconお疲れ様です☺️
takasshii.icon夜遅くまで偉い!!!!!
ichimura.icon 眠いですけど、まだ終わってなくて...残り頑張ります
takasshii.iconファイトだ〜がんばろ〜!
ichimura.icon オー!!!
ブローカートポロジの欠点解消が目的
ワークフローを管理する
構成されるコンポーネント
開始イベント
開始イベント用のキューに送られる
イベントメディエーターに受け入れられる
イベントキュー
イベントメディエーター
イベント処理に必要なステップのみ知っている
対応する処理イベントを生成
処理後、専用のイベントチャンネルに送信する
イベントチャンネル
専用のイベントチャンネルで待ち受け
イベント処理後、メディエータに完了を伝える
イベントプロセッサー
特定のドメインや、イベントのグループに関連づけられて、複数のメディエーターが存在する
例
顧客関連イベント
新規顧客登録やプロフィール更新など
注文アクティビティ
ショッピングカートにアイテムを追加してチェックアウトなど
複雑さに応じて実装を変えられる
メディエーターは処理に応じたものが複数ある
実装
単純イベント向けメディエーターを経由
メディエーターへの委託モデル
図14.6
ブローカーとの違い
ワークフローに関する知識と制御を持つ
処理イベントの意味と使用方法が異なる
ブローカーは通知
メディエーターはコマンド(命令)
メリット
単一障害点の問題が軽減される
全体のスループットとパフォーマンスを向上
デメリット
複雑なイベントフロー内で発生する動的な処理を宣言的にモデル化することが難しい
メディエータとブローカーの両方を組み合わせたもので対応
イベントプロセッサーと同様にメディエーターもスケーリング
ボトルネックに
パフォーマンスを向上しづらい
非同期の能力
非同期ベースなので、システム全体の応答性を向上
例 コメント投稿の挙動
コメントに3000msかかる
いくつかの解析エンジンにかけるため
禁止用語チェック
語法チェック
コンテキストチェック
サービス受信にも50msかかる
同期通信では、全体で3000msほどかかり、完全に投稿が確認できたら認証されたことを通知
非同期通信ではユーザーが必要な情報だけに絞って応答できる
takasshii.iconここから入れ替わるよ
非同期ワークフローにおけるエラー処理
ワークフロー委譲を行うことが特徴
図
順番
1. イベントプロデューサーでエラーが発生
2. イベントチャンネルのキューを通して、エラーをイベントコンシューマーに伝搬
3. イベントチャンネルのキューを通して、エラーをワークプロセッサーに伝搬
4. ワークプロセッサでエラー処理を行う
5. エラー処理を行い、訂正したものをイベントチャンネルのキューに追加
メリット
エラーが発生している間もイベントチャンネル内のキューに入っているイベントが処理されるため、全体的な応答性は高い
時間をかけてエラーの原因を探る場合も全体が停止しない
ワークフローイベントパターンを採用することで得られるメリットの例
図
1. Long型のところに8756 SHARESという値が入ってしまった
2. Exception in thread "main" java.lang.NumberFormatException:というエラーが発生した
3. エラー処理をワークフロープロセッサーに委譲する
4. エラーを分析し、 8756 SHARESから不必要な部分を削除し8756にする
5. 再度イベントチャンネルのキューに投げて再リトライできる
takasshii.iconエラーが正常に処理されるようになるよ!!
デメリット
エラーが再送信されたときに処理が順番に行われない
でも解決策はある(株取引の例を考えるよ👀)
1. ワークフロープロセッサーがエラーの取引を処理する
2. エラーの取引の証券口座番号をキューAに入れておく
3. キューAと一致する証券口座番号があったら、その取引をキューBに入れて保存する
4. エラーの取引が来たらキューBに保存した取引を順に行う
データロスの防止
非同期通信を扱う際には,データロスが最大の懸念事項
データロスが発生する例
図
1. キューにイベントプロセッサーAからのメッセージが届かない。または、届いたとしても、イベントプロセッサーがそのメッセージを取得する前にブローカーが落ちてしまう。
2. 次に処理するメッセージをキューから取得した後、そのイベントを処理する前にイベントプロセッサーBがクラッシュしてしまう。
3. 何らかのデータエラーが理由で、イベントプロセッサーBがメッセージをデータベースに永続化できない。
1 メッセージがキューに到達しないことへの対処法
永続的なメッセージキューを用いる
永続的(=物理的なデータストア)にデータが保存されるため,メッセージブローカーが落ちたとしても復旧が可能
メッセージキューに同期送信を行う
メッセージが永続化されるまでプロデューサーが待つ
2 イベントを処理する前にイベントプロセッサーが落ちてしまうことへの対処法
デフォルトのキューは自動応答モード
キューから取り出されたメッセージはキューから削除される
クライアント応用モードにすると行われること
メッセージをキューに残す
クラッシュしてもメッセージがキューに保存されている
クライアントIDをメッセージにつける
他のコンシューマーがメッセージを読めない
takasshii.iconこのことかな?参考文献 3 イベントプロセッサーがDBに永続化できないことへの対処法
データベースコミット介したACIDトランザクションを利用し,永続化されたことを確認してからキューのデータを削除する
データベースコミットが発生 = DBに永続化されたことが保証される仕組み
LPSという機能を使うとできる
まとめ
図
ブロードキャスト能力
イベント駆動アーキテクチャの特徴にメッセージの受信相手や目的を気にせずにイベントをブロードキャストする能力がある
メリット
イベントプロセッサ間の結合をめちゃめちゃ疎にできる
頻繁にイベントが入れ替わり,多くのものに影響を与える可能性がある場合に便利
何も考えなくてもブロードキャストすれば済んじゃう!
イベント駆動アーキテクチャでの同期通信
どうしても同期通信が必要な場面がある
リクエスト、リプライキューから構成される
図
1. 非同期的にリクエストキューに開始要求がなされる
2. イベントプロデューサーに制御が戻される
3. リプライキューがメッセージを受け取るまでブロックして応答を待つ
4. メッセージを受信してリプライキューに応答を渡す
5. 待ち合わせ処理を行う
実際の実装
一般的な方法
図
特定のリクエスト専用のキュー
リクエストが行われた時に作成され、終了した時に削除される
図
非常に単純
リクエストのたびにテンポラリーキューを作成、削除するのはパフォーマンスを低下させる
リクエストベースとイベントベースの間をとる
リクエストベースが向いている場合
確実性が必要
管理が行われる
構造化されたデータ駆動型のリクエスト
イベントベースが向いている場合
複雑で動的な処理
高い応答性とスケールを必要とするアクションベースのイベント
これらはトレードオフ
table:両者の比較
イベントベースのメリット デメリット
動的なユーザーコンテンツに対する応答性の向上 結果整合性のみをサポート
スケーラビリティ・弾力性の向上処理 フローの制御性の低下
アジリティとチェンジマネジメントの向上 イベントフローの結果に対する確実性の低下
適応性と拡張性の向上テストやデバッグが難しい
充実した対応力とパフォーマンス
リアルタイムでの意思決定が可能になる
状況認識に対する反応の良さ
イベント駆動と他のアーキテクチャスタイルを併用したハイブリットアーキテクチャを形成するものも多い
イベント駆動+マイクロサービス
イベント駆動+スペースベース
イベント駆動+マイクロカーネル
イベント駆動+パイプライン
table:イベント駆動アーキテクチャ
分割タイプ 技術
量子数 1(モノリシック)以上
デプロイ容易性 ☆☆☆
弾力性 ☆☆☆
進化性 ☆☆☆☆☆
耐障害性 ☆☆☆☆☆
モジュール性 ☆☆☆☆
全体的なコスト(の安価さ) ☆☆☆
パフォーマンス ☆☆☆☆☆
信頼性 ☆☆☆
スケーラビリティ ☆☆☆☆☆
シンプルさ ☆
テスト容易性 ☆☆
応用
code:sample.kt
質疑応答
Mediatorとオーケストレーションの意味の違いは何か?